mod data;

#[derive(Default)]
pub struct TrieNode {
    children: std::collections::HashMap<char, TrieNode>,
    is_end: bool,
    value: Option<String>,
}

impl TrieNode {
    pub fn new() -> Self {
        Self {
            children: std::collections::HashMap::new(),
            is_end: false,
            value: None,
        }
    }

    pub fn insert(&mut self, key: &str, value: &str) {
        let mut current = self;
        for ch in key.chars() {
            current = current.children.entry(ch).or_default();
        }
        current.is_end = true;
        current.value = Some(value.to_string());
    }

    pub fn find_longest_match(&self, text: &str) -> Option<(usize, String)> {
        let mut current = self;
        let mut last_match: Option<(usize, String)> = None;
        let chars: Vec<char> = text.chars().collect();

        for (i, &ch) in chars.iter().enumerate() {
            if let Some(next) = current.children.get(&ch) {
                current = next;
                if current.is_end {
                    if let Some(ref value) = current.value {
                        last_match = Some((i + 1, value.clone()));
                    }
                }
            } else {
                break;
            }
        }

        last_match
    }
}

pub fn converter(input: &str, tp: &str) -> String {
    use data::{S2T, T2S};

    let convert_map = match tp {
        "s2t" => &*S2T,
        "t2s" => &*T2S,
        _ => panic!("Unknown type!")
    };

    let mut result = String::new();
    let mut i = 0;
    let text: Vec<char> = input.chars().collect();

    while i < text.len() {
        let remaining: String = text[i..].iter().collect();
        if let Some((len, value)) = convert_map.find_longest_match(&remaining) {
            result.push_str(&value);
            i += len;
        } else {
            result.push(text[i]);
            i += 1;
        }
    }

    result
}